package com.todo.auth.service;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.todo.auth.common.convert.UserAuthConvert;
import com.todo.auth.controller.request.LogOffAccountParam;
import com.todo.auth.controller.request.TransferPasswordParam;
import com.todo.auth.controller.request.UserNameLoginParam;
import com.todo.auth.controller.request.UserNameRegisterParam;
import com.todo.auth.controller.response.UserTokenVO;
import com.todo.auth.remote.UserAccountRemoteService;
import com.todo.auth.tool.TokenService;
import com.todo.auth.entity.UserAccountDetail;
import com.todo.common.common.constants.Constants;
import com.todo.common.common.entity.CurrentUser;
import com.todo.common.common.entity.response.BizResponse;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.common.utils.StringUtils;
import com.todo.component.redis.RedisService;
import com.todo.user.api.request.QueryUserAccountByUserNameRequest;
import com.todo.user.api.request.RegisterUserAccountByNameRequest;
import com.todo.user.api.request.RemoveUserAccountByUserNameRequest;
import com.todo.user.api.request.UpdateUserSecretRequest;
import com.todo.user.api.response.UserAccountResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author azhebuxing
 * @date 2025/2/21 01:52
 * @description
 */
@Slf4j
@Service
public class UserAccountLoginService {

    @Autowired
    private TokenService tokenService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserAccountRemoteService userAccountRemote;
    @Resource
    private RedisService redisService;


    public BizResponse<UserTokenVO> registerByName(UserNameRegisterParam param) {
        if (param == null || StringUtils.isBlank(param.getUserName()) || StringUtils.isBlank(param.getPassword())) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (!verifyUserName(param.getUserName())) {
            throw new BizException(BizErrorCodeEnum.SAME_USER_NAME);
        }
        String password = decryptPassword(param.getPassword());
        String encodePassword = passwordEncoder.encode(password);
        RegisterUserAccountByNameRequest request = new RegisterUserAccountByNameRequest();
        request.setUserName(param.getUserName());
        request.setPassword(encodePassword);
        BizResponse<Boolean> insertResult = userAccountRemote.registerUserAccountByName(request);
        if (insertResult == null || !insertResult.isSuccess() || !insertResult.getData()) {
            log.error("UserAccountAggService#registerByName 用户注册失败 userName：【{}】", param.getUserName());
            throw new BizException(BizErrorCodeEnum.OPERATION_FAILED);
        }
        UserNameLoginParam loginParam = new UserNameLoginParam();
        loginParam.setUserName(param.getUserName());
        loginParam.setPassword(param.getPassword());
        return login(loginParam);
    }

    public Boolean verifyUserName(String userName) {
        if (StringUtils.isBlank(userName)) {
            log.warn("UserAccountAggService#verifyUserName 用户名称校验失败，数据为空 ");
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        String logKey = String.format(Constants.LOGIN_USER_KEY, userName);
        String cached = redisService.get(logKey);
        if (StringUtils.isNotBlank(cached)) {
            return false;
        }
        QueryUserAccountByUserNameRequest request = new QueryUserAccountByUserNameRequest();
        request.setUserName(userName);
        BizResponse<UserAccountResponse> response = userAccountRemote.queryUserAccountByUserName(request);
        if (response == null || !response.isSuccess() || response.getData() == null) {
            return true;
        }
        return false;
    }


    public BizResponse<UserTokenVO> login(UserNameLoginParam param) {
        if (param == null || StringUtils.isEmpty(param.getUserName()) || StringUtils.isEmpty(param.getPassword())) {
            log.error("UserAccountAggService#login 登录失败，数据缺失 userName：【{}】", param.getUserName());
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        String userName = param.getUserName();
        String password = decryptPassword(param.getPassword());
        UserAccountDetail userAccountDetail = (UserAccountDetail) queryUserDetailsByUserName(userName);
        if (userAccountDetail == null || userAccountDetail.getUserAccount() == null) {
            log.error("UserAccountAggService#login 登录失败，根据userName获取用户信息为空 userName：【{}】", userName);
            throw new BizException(BizErrorCodeEnum.USER_DOES_NOT_EXISTS);
        }
        //密码核对
        if (!passwordEncoder.matches(password, userAccountDetail.getPassword())) {
            // TODO 后续做多次登录失败控制
            log.warn("UserAccountAggService#login 登录失败，账户密码错误 userName:【{}】", userName);
            throw new BizException(BizErrorCodeEnum.PASSWORD_ERROR);
        }
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userAccountDetail, null, userAccountDetail.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = tokenService.generateToken(userAccountDetail, true);
        //保存登陆的缓存信息
        String logKey = String.format(Constants.LOGIN_USER_KEY, userName);
        CurrentUser currentUser = UserAuthConvert.buildCurrentUser(userAccountDetail);
        currentUser.setToken(token);
        redisService.set(logKey, JSONObject.toJSONString(currentUser), Constants.LOGIN_USER_EXPIRE);
        log.info("UserAccountAggService#login 登录成功 userName:【{}】,token:【{}】", userName, token);
        UserTokenVO userTokenVO = new UserTokenVO();
        userTokenVO.setToken(token);
        return new BizResponse<>(userTokenVO);
    }


    /**
     * 获取用户detail信息
     *
     * @param userName
     * @return
     */
    public UserDetails queryUserDetailsByUserName(String userName) {
        if (StringUtils.isEmpty(userName)) {
            return null;
        }
        QueryUserAccountByUserNameRequest request = new QueryUserAccountByUserNameRequest();
        request.setUserName(userName);
        BizResponse<UserAccountResponse> response = userAccountRemote.queryUserAccountByUserName(request);
        if (response == null || !response.isSuccess() || response.getData() == null) {
            log.warn("UserAccountAggService#queryUserDetailsByUserName 根据userName查询用户详情做登录操作失败，数据为空 userName：【{}】", userName);
            return null;
        }
        UserAccountResponse userAccountResponse = response.getData();
        UserAccountDetail.UserAccount userAccount = UserAuthConvert.convertToUserAccount(userAccountResponse);
        UserAccountDetail userAccountDetail = new UserAccountDetail(userAccount);
        userAccountDetail.fillLoginInfo();
        return userAccountDetail;
    }


    public BizResponse<Boolean> logOffAccount(LogOffAccountParam param) {
        if (param == null || param.get_user() == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        RemoveUserAccountByUserNameRequest request = new RemoveUserAccountByUserNameRequest();
        request.setUserName(param.get_user().getUserName());
        BizResponse<Boolean> response = userAccountRemote.removeUserAccountByUserName(request);
        if (response == null || !response.isSuccess() || response.getData() == null || !response.getData()) {
            log.error("UserAccountAggService#logOffAccount 用户注销失败 userName：【{}】", param.get_user().getUserName());
            throw new BizException(BizErrorCodeEnum.OPERATION_FAILED);
        }
        //剔除登陆缓存信息
        String logKey = String.format(Constants.LOGIN_USER_KEY, param.get_user().getUserName());
        redisService.del(logKey);
        return BizResponse.success(true);
    }


    public BizResponse<UserTokenVO> transferPassword(TransferPasswordParam param) {
        if (param == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        UserAccountDetail userAccountDetail = (UserAccountDetail) queryUserDetailsByUserName(param.get_user().getUserName());
        if (userAccountDetail == null || userAccountDetail.getUserAccount() == null) {
            log.error("UserAccountAggService#transferPassword 登录信息验证失败，根据userName获取用户信息为空 userName：【{}】", param.get_user().getUserName());
            throw new BizException(BizErrorCodeEnum.USER_DOES_NOT_EXISTS);
        }
        //密码核对
        if (!passwordEncoder.matches(param.getOldPassword(), userAccountDetail.getPassword())) {
            // TODO 后续做多次登录失败控制
            log.warn("UserAccountAggService#transferPassword 登录信息验证失败，账户密码错误 userName:【{}】", param.get_user().getUserName());
            throw new BizException(BizErrorCodeEnum.PASSWORD_ERROR);
        }

        UpdateUserSecretRequest request = new UpdateUserSecretRequest();
        request.setUserName(param.get_user().getUserName());
        request.setOldPassword(param.getOldPassword());
        request.setNewPassword(param.getNewPassword());
        BizResponse<Boolean> response = userAccountRemote.updateUserSecret(request);
        if (response != null && response.isSuccess() && response.getData() != null && Boolean.TRUE.equals(response.getData())) {
            UserNameLoginParam loginParam = new UserNameLoginParam();
            loginParam.setUserName(param.get_user().getUserName());
            loginParam.setPassword(param.getNewPassword());
            return login(loginParam);
        }
        return BizResponse.operationFailed();
    }


    public String decryptPassword(String originalPassword) {
        byte[] decryptBytes = Base64.decode(originalPassword);

        return StrUtil.str(decryptBytes, CharsetUtil.CHARSET_UTF_8);
    }


    //    public Boolean registerByPhone(String username, String telephone, String authCode) {
//        if (StringUtils.isBlank(username) || StringUtils.isBlank(telephone)) {
//            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
//        }
//        if (!verifyUserName(username)) {
//            log.warn("UserAccountAggService#registerByPhone 注册用户信息失败，用户名重复 telephone：【{}】", telephone);
//            throw new BizException(BizErrorCodeEnum.SAME_USER_NAME);
//        }
//        if (!PhoneUtil.isPhone(telephone)) {
//            log.warn("UserAccountAggService#registerByPhone 注册用户信息失败，非正常手机号 telephone：【{}】", telephone);
//            throw new BizException(BizErrorCodeEnum.PHONE_ERROR);
//        }
//        if (!verifyAuthCode(telephone, authCode)) {
//            log.warn("UserAccountAggService#registerByPhone 注册用户信息失败，授权码过期 telephone：【{}】", telephone);
//            throw new BizException(BizErrorCodeEnum.OPERATE_AUTH_EXPIRE);
//        }
//        Boolean insertResult = userAccountRemote.insertUserAccount(username, telephone, null);
//        //TODO 数据登陆
//        return insertResult;
//    }
//
//    /**
//     * 验证码校验
//     *
//     * @param telephone
//     * @param authCode
//     * @return
//     */
//    private boolean verifyAuthCode(String telephone, String authCode) {
//        String cacheValue = userCacheRemote.getAuthCode(telephone);
//        return authCode.equals(cacheValue);
//    }
//
//    public String generateAuthCode(String telephone) {
//        StringBuilder sb = new StringBuilder();
//        Random random = new Random();
//        for (int i = 0; i < 6; i++) {
//            sb.append(random.nextInt(10));
//        }
//        userCacheRemote.setAuthCode(telephone, sb.toString());
//        return sb.toString();
//    }
}
